package net.folab.fo.vm;

import net.folab.fo.vm.BindableEval;
import net.folab.fo.vm.Evaluateable;
import net.folab.fo.vm.FoBoolean;
import net.folab.fo.vm.Bindable;
import net.folab.fo.vm.FoInteger;

public class _factorial implements Bindable<FoInteger, FoInteger> {


    @Override
    public Evaluateable<FoInteger> bind(Evaluateable<FoInteger> parameter) {
        Evaluateable<FoBoolean> bind_isLessThantTwo = _isLessThanTwo.bind(parameter);
        Evaluateable<FoInteger> bind_next = _next.bind(parameter);

        _if<FoInteger> _if = new _if<FoInteger>();
        _if_0<FoInteger> bind0 = _if.bind(bind_isLessThantTwo);
        _if_1<FoInteger> bind1 = bind0.bind(new FoInteger(1));
        return bind1.bind(new _multiply(parameter).bind(bind_next));
    }

    public final Bindable<FoInteger, FoBoolean> _isLessThanTwo = new Bindable<FoInteger, FoBoolean>() {

        @Override
        public Evaluateable<FoBoolean> bind(Evaluateable<FoInteger> parameter) {
            return new _isLessThan(parameter).bind(new FoInteger(2));
        }

    };

    public final Bindable<FoInteger, FoInteger> _next = new Bindable<FoInteger, FoInteger>() {

        @Override
        public Evaluateable<FoInteger> bind(Evaluateable<FoInteger> parameter) {
            Evaluateable<FoInteger> bind = new _subtract(parameter).bind(new FoInteger(1));
            BindableEval<FoInteger, FoInteger> e = new BindableEval<FoInteger, FoInteger>() {

                @Override
                public Evaluateable<FoInteger> bind(final Evaluateable<FoInteger> parameter) {
                    return new Evaluateable<FoInteger>() {

                        @Override
                        public FoInteger evaluate() {
                            return _factorial.this.bind(parameter).evaluate();
                        }
                    };
                }

                @Override
                public Bindable<FoInteger, FoInteger> evaluate() {
                    // TODO Auto-generated method stub
                    throw new UnsupportedOperationException("Not yet implemented");
                }
            };
            return e.bind(bind);
        }


    };
}
